笔记《编程的原则:改善代码质量的101个方法》

第一章 前提 编程永恒的真理

如果一个人不知道他要驶向哪个码头,那么任何风都不会是顺风。 ——塞涅卡

1.编程没有银弹

No Silver Bullet in programming.

因为软件在本质上具有难度,复杂性、同步性、可变性、不可见性,编程中没有万能解决方案。

我们要学习软件开发的历史,脚踏实地地对软件进行改善。

*软件开发现场需要用到的技术大多属于非本质的东西,构建环境、编程语言、库和框架等都是软件的非本质部分。非本质部分更容易改善,非本质部分的活动呢对于推进软件本质部分的活动有着巨大的贡献,其中最有效的是自动化。

2.代码即设计文档

Code as design.

产品的改善在设计环节进行

编程属于设计行为,在软件开发过程中生成的所有文本,其中能真正称得上工程文档的,只有代码。CASE工具和UML只能起到辅助作用。

代码能很好地表达“怎么做”和“是什么”,却不能表达“为什么”,也就是设计理由。将设计理由描述在文档中,能为维护负责人提供判断材料。

3.代码必然被修改

Code will be changed.

代码是无常的,软件在本质上具有复杂性,这就决定了它不可能是完美无暇的。没有写完就扔的一次性代码。

编程中的任何一个判断都要以代码会被修改为前提。

第二章 准则 编程的指导方针

在我们尚未给予自己支配本身的力量时,解放我们精神的所有行为,都是百害而无一益的。——歌德

4.KISS原则

Keep it simple,stupid,or Keep it short and simple.

保持代码简洁。

随意修改代码会使代码变得越来越复杂,越来越没有秩序。

简洁的代码,其各个组成要素也是简洁的,各要素承担的责任也都降到了最小,各要素之间的关系也比较简单。简洁的代码可读性高,容易理解,便于修改。各要素职责明确,使得测试也变得简单易行。

less is more,不写多余的代码,使代码保持简洁,防范于未然。

奥卡姆剃刀原理:主张不应假设非必要的前提来说明某个事物。当一个事物存在多种解释时,最简单的那个解释是正确的。

5.DRY原则

Don’t Repeat Yourself.

不要重复。

代码一旦出现重复,故障修复、添加功能等,代码的改善措施就会变得难以实施,我们会遇到如下困难:

  • 代码的可读性下降
  • 代码难以修改
  • 没有测试

不可以重复写相同的代码,严禁复制粘贴代码。

我们可以通过对代码执行抽象化操作来消除重复。其实就是给整个处理命名,将其函数化、模块化。至于数据,则需要起个名字定义为常量。抽象化有几个优点:

  • 减少了代码量,减轻了阅读负担
  • 逻辑和数据有了名称,可读性变高了
  • 代码的修改操作变得简单
  • 抽象部分易于重复使用

*设计模式、自动化也是DRY的处理。

*WET,Write Every Time,与DRY相对,表示重复同样的事情,常用于讽刺那些没有DRY的代码。

*OFOP,One Fact in One Place,一个地方只有一个事实,是数据库理论设计中表设计的一项重要原则。

*OAOO,Once and Only Once,有且仅有一次,不可以出现重复,与DRY意思目的相同但范围要小,只能用在编程语法上。

6.YAGNI

You Aren’t Going to Need It.

你不会需要它。

不能以“可能会用到”为动机编写代码,人们不能预测出软件的变化,写出超强的代码,我们只写所需最低限度的代码。比起通用性,我们更应该重视单纯性,

*DSTTCPW,Do the simplest Thing that could possibly work,在可行方案中选取最简单的方案执行,同YAGNI。

7.PIE

Program Intently and Expressively.

编程要表达出意图。

读代码的次数远比写代码的次数多。避免打地鼠式开发。

*文学编程,literate programming,将代码本身当作文档的编程方法,代码和文档并不分开编写,二者会编写在一个文本中。

8.SLAP

Single Level of Abstraction Principle.

单一抽象层次原则

在编写代码时,我们要将高级别的抽象化概念和低级别的抽象化概念分离。在分离时不能只有高低两层,我们要根据功能的复杂程度对抽象化概念进行分离,然后统一各层的抽象级别。也就是说,我们要根据抽象级别对函数进行分割,并且将同一函数中的代码统一为同一个抽象级别。

我们要将函数结构化,将处理转换为意图清晰、由抽象化级别一致的多个步骤组成的函数。参考写文章时的步骤来实现SLAP。

9.OCP

Open-Closed Principle.

开闭原则

对扩展开放、对修改关闭两个属性。

  • 代码的行为可以扩展
  • 对代码对行为进行扩展时,其他代码完全不会受到影响。

实现:设置接口。

面向对象的多态性是实现OCP的代表技术。

*GRASP,General Responsibility Assignment Software Pattern,通用职责分配软件模式。

10.名字很重要

Naming is important

写代码前先决定名字。

  • 名字中要尽量多包含信息
  • 名字不能有歧义
  • 名字说明的是效果和目的,而不是手段
  • 可以通过先写测试程序后写处理的方式检查一下自己取的名字是否合适
  • 名字要能念出来
  • 名字要能搜索出来。

*心理映射:读代码的人看到某元素名字后需要先在心里把它转换成自己知道的东西,这个过程就是心理映射,我们应该极力避免这种情况发生。

有一种叫做“名字可逆性”的命名思路,主张名字必须能还原其所指内容的说明文本。要想满足这一条件,就需要进行环回检测。先通过内容的说明文本来想名字,再通过名字倒推出说明文本。按照说明文本、名字、说明文本的顺序绕一圈回来后,如果说明文本一致,那这个名字就是好名字,如果不一致就需要我们注意了。

第三章 思想 编程的意识形态

11.编程理论

A theory of programming.

高质量的代码是指拥有多种扩展方法、不存在多余要素、可读性高、易于理解的代码。

编程中有一套理论专门用来指导人们实现这种高质量的代码,该理由由以下三个思想作为支撑:

  • 交流
  • 简洁
  • 灵活性

编程在不同的问题领域有不同的技术和模式。

有6个桥梁可以连接思想与编程:

  • 效应局部化
  • 重复最少化
  • 逻辑与数据的一体化
  • 对称性
  • 声明式表达
  • 变动率

12.交流

Communication

代码也是一种文档,文档的本质在于交流,顺利的开放源于顺利的交流。

13.简洁

Simplicity

消除代码的复杂性,分清代码中的“玉”(本质部分)与“石”(其他元素)。

14.灵活性

Flexibility

代码的灵活性是指修改代码的难易程度。灵活是指在添加新代码时,已有代码能够不受影响,不产生冲突、不出现排斥,在保证自身不遭到破坏的前提下灵活地接纳新代码。

15.效应局部化

Local consequences.

指将修改带来的影响控制在局部。减少修改带来的影响,效应指修改带来的影响。围绕该原则产生了许多技术,模块化就是其中之一。

在编写代码的时候,要让关系紧密的代码集中在一起,同时保证关联性较弱的代码不互相依赖。

16. 重复最少化

Minimize repetition

极力消除重复,如函数化。

17.逻辑与数据的一体化

Logic and Data together.

修改代码时往往需要同时修改逻辑与该逻辑处理的数据。把逻辑和该逻辑处理的数据放在相近的位置,即同一函数或同一模块内。

18.对称性

Symmetry

相同的思路在代码的任何地方都以相同的形式表现出来。同类的东西,要使用相同的等级来表示。

  • 如果有“添加”方法,就创建与之对应的“删除”方法
  • 同组的函数用相同的参数
  • 让同一个模块里的数据拥有相同的生存周期
  • 函数内所有调用函数的抽象级别要相同

19.声明式表达

Declarative Expression

声明式编程描述的是问题的定义,也就是当前问题的性质及解决问题时应满足的限制条件。

声明式的代码没有流程方面的限制,这种单纯阐述事实的表达方式能够提升代码的可读性。

函数式语言就是声明式通用编程语言中的一个典型代表。另外HTML、CSS、SQL等非通用语言也都是声明式的。

另一方面,当编程范式使用了命令式语言时,我们也要在代码中合适的部分使用声明表达,以获取声明式带来的优势,代表方法有注释和DSL。

20.变动率

Rate of Change

变动率体现了修改代码的时间点,变动率相同意味着代码在同一时间点被修改。

同时修改的元素要放在同一个地方,在不同时间点修改的元素要放不同的地方

21.软件架构基本技法

Enabling techniques for Architecturea.

软件架构基本技法共有以下10种:

  • 抽象
  • 封装
  • 信息隐藏
  • 打包
  • 关注点分离
  • 充足性、完整性、原始性
  • 策略和实现的分离
  • 接口与实现的分离
  • 单一引用点
  • 分治

22.抽象

Abstract

指在概念上明确划清界限,由“舍象”和“一般化”这两个观点组合而成。

  • 舍象:舍去复杂对象的几个性质,只关注其特定的性质
  • 一般化:从具体对象中抽出共同的性质,将其固定为更加通用的概念。

23.封装

Encapsulation

通过分组,相互关联的元素被集中到一个模块中,共同担负起一个抽象概念。

24.信息隐藏

Information Hiding

只展示必要的信息,隐藏内部信息。

25.打包

Packaging

将代码中的相关元素封装成模块,可以起到整理代码、降低复杂度的作用。当软件规模大到一定程度后,模块数量非常多,此时就需要对模块群进行分组,也就是打包。

26.关注点分离

Separation of Concerns

在编程领域,关注点分离的代表技术时AOP、在设计技法中如MVC。

27.充足性、完整性、原始性

Sufficiency、Completeness、Primitiveness

表达要充足、完备且精练。

28.策略和实现的分离

Separation of Policy and Implementation.

模块可以承载策略或实现,但是一个模块不可以同时承载二者。

29.接口与实现的分离

Separation of Interface and Implementation

使用者只需理解接口

30.单一引用点

Single Point of Reference

模块的各元素只定义一次。

31.分治

Divide and Conquer

将大问题分割成小问题,然后逐个解决

32.软件架构的非功能需求

Non-functional requirement for Architecture

非功能需求包含以下几种观点:

  • 易变性
  • 互操作性
  • 效率性
  • 可靠性
  • 可测试性
  • 可重复性

33.易变性

Changeability

轻松修改软件的能力,要求软件能够轻易修改、轻易扩展、轻易重组、轻易移植到其他平台。

34.互操作性

Interoperability

指软件与其他软件交互的能力,要求不同的软件之间使用同一交换方式来交换数据、读取相同格式的文件、使用相同的协议等,从而实现相互连接的状态。

35.效率性

Efficiency

指软件在运行过程中使用资源发挥性能的能力。

  • 时间效率性
  • 资源效率性

*为了避免各个模块直接关联,有时会在模块之间导入“媒介模块”,这种方法称为间接化。间接化有利于维持低耦合性,保持较高的可维护性、可扩展性和可复用性。但有可能会让处理变得冗长,对效率造成影响。

36.可靠性

Reliability

软件在异常情况下或在被非法、非常规使用时维持自身功能的能力:

  • 容错
  • 健壮性

37.可测试性

Testability

软件有效且高效地进行测试的能力。

提高可测试性的关键在于消除模块之间的依赖关系。

38.可复用性

Reusability

表现:

  • 重复使用现有代码的软件开发;
  • 以重复为目的的软件开发

创建可重复使用的模块,“三之法则”:

  • 三倍难度法则:开发可重复使用的模块的难度是开发在单一软件中使用的模块的难度的三倍。
  • 三种测试法则:可重复使用的模块在共享之前需要在三个不同的软件中通过测试。

39.七个设计原理

Seven design principles

我们在设计代码结构时应考虑的核心观点,目的是避免打吗中存在故障隐患。代码审查的判断标准:

  • 简单性原理
  • 同构原理
  • 对称原理
  • 层次原理
  • 线性原理(透明原理)
  • 清晰原理
  • 安全原理

40.简单性原理

Simplicity Principle

追求简单,让初学者一眼就能看懂。

bug喜欢出现在复杂的地方。

41.同构原理

Isomorphism Principle

力求规范,同等对待相同的东西,坚持不搞特殊,同等对待。如数值单位统一、函数参数个数统一。

编写符合规范的代码。

42.对称原理

Symmetry Principle

讲究形式上的对称,有上就有下,有加就有减。有助于帮助推测后面的代码,能防范我们在思考问题时出现遗漏。

43.层次原理

Hierarchy Principle

在结构上讲究层次,注意事物的主从关系、前后关系和本末关系。

44.线性原理

Linearity Principle

透明原理,让处理流程尽可能走直线。

复杂的处理流程上故障的温床。

45.清晰原理

Clarity Principle

注意逻辑的清晰性。

46.安全原理

Safty Principle

注意安全性,采用相对安全的方法来对具有不确定性的、模糊的部分进行设计和编程。

47.UNIX思想

UNIX Culture

UNIX思想原则:

  • 模块化原则
  • 清晰原则
  • 组合原则
  • 分离原则
  • 简单原则
  • 简约原则
  • 透明性原则
  • 健壮性原则
  • 表达性原则
  • 最小意外原则
  • 沉默原则
  • 修复原则
  • 经济原则
  • 生成原则
  • 优化原则
  • 多样性原则
  • 可扩展性原则

48.模块化原则

Rule of Modularity

模块之间的关系应简洁,应减少模块的接口。

49.清晰原则

Rule of Clarity

代码不应该巧妙,而应该清晰。

50.组合原则

Rule of Composition

要保证软件能和其他软件组合使用,将软件做成一个尽量简单的过滤器。

51.分离原则

Rule of Separation

从机制中分离出策略

  • 策略:依赖于软件前提的部分,在代码中相对不稳定,比如业务逻辑和用户接口;
  • 机制:不依赖于软件前提的自我独立的部分,在代码中相对稳定,比如绘图算法。

对软件中稳定的部分和不稳定的部分分开进行管理。

52.简单原则

Rule of Simplicity

将代码设计得足够简单。

营造“简单即美丽”的文化氛围。

53.简约原则

Rule of Parsimony

不写大代码(代码量大、复杂指数大)

54.透明性原则

Rule of Transparency

保证我们能从外部清楚看到软件的运行状态,有助于调试。

  • 透明性:让人一眼就能理解“软件正在做什么”以及“软件是怎么做的”
  • 公示性:可以监视或表现软件的内部状态。

55.健壮性原则

Rule of Robustness

让软件具有健壮性,不仅能在一般条件下正常运行,还能在预想之外的条件下提供实适当的服务。也可以称为坚固性。

56.表达性原则

Rule of Representation

代码中的信息要尽量用数据而非逻辑来表达。

57.最小意外原则

Rule of Least Surprise

接口的设计尽量不让使用者感到意外,要避开毫无意义的新奇设计以及过度取巧的设计。

活用用户已有知识

  • 参考类似的软件来设计接口
  • 考虑目标用户的特征
  • 注意传统
  • 避免“相似但稍有不同”

58.沉默原则

Rule of Silence

软件应将显示内容控制在最少的程度,默默执行自己的工作。

将输出的信息控制到最少,只输出重要的信息。

  • 发生错误时只将真正错误的部分作为标准错误输出,不输出所需范围之外的任何数据;
  • 如果因为调试而需要输出信息来显示当前运行状况,则可以制作一个具有冗余模式的开关,让开关默认处于关闭状态。

59.修复原则

Rule of Repair

在软件运行过程中,一旦出现错误且修复原则,就应该立即停止处理。此外,软件在发生错误时要有明显的提示。

60.经济原则

Rule of Economy

程序员的时间是宝贵资源,值得珍惜。

以下会浪费资源:

  • 硬件性能不足
  • 可用软件的限制
  • 环境相关的规则或限制

61.生成原则

Rule of Generation

编写用于生成代码的代码,生成出来的代码成本低且质量高,我们要减少手动操作。

62.优化原则

Rule of Optimization

编程中的优化指性能调优,包括提高运行速度、优化内存和硬盘等计算机资源的使用率。

先确保代码的正确性再想办法提高运行速度。

63.多样性原则

Rule of Diversity

软件开发不可能存在唯一正确的方法,容许多样的选择,不懈追求更好的方案。

64.可扩展性原则

Rule of Extensibility

软件必须扩展,设计时留有扩展的余地。

我们要采用可插拔式设计,自我描述性的数据格式。

65.UNIX哲学

UNIX哲学定理:

  • 小就是美
  • 工作唯一
  • 今早创建原型
  • 可移植性优先于效率
  • 文本数据
  • 充分利用软件的杠杆效应
  • 活用shell脚本
  • 避开交互式用户接口
  • 过滤器化

66.小就是美

Small is beautiful

软件规模越小越美丽(价值高)

  • 易于理解
  • 容易维护
  • 给计算机资源带来的负担较小
  • 便于同其他软件结合

67.工作唯一

Make each program do one thing well

一个软件只负责一项工作,专注于一项工作,让软件变得纯粹。

68.尽早创建原型

Build a prototype as soon as possible

等待完整的功能说明书只会浪费时间,通过原型进行学习还能加大开发的动力。

  • 提早发现前提性质的错误
  • 减少需求不完备导致的返工
  • 能提早开始排查错误

*任何系统都有一个改良的过程,都会按照“第一系统”、“第二系统”、“第三系统”的顺序发布:

  • 第一系统:性能良好、但欠缺一部分必要的功能
  • 第二系统:天平导向另一边,在牺牲性能的前提下添加了许多功能
  • 第三系统:(我们的目标),性能与功能之间取得了恰当的平衡,系统保留了真正有用的功能。

69.可移植性优先于效率

Choose portability over efficiency

衡量软件是否成本的标准之一是软件能在多少中平台上运行。

70.文本数据

Store numerical data in flat ASCII files

将数值数据保存在ASCII平面文件内。

文本文件上万能的,应选用不受语言和操作系统限制的标准格式,如CSV、XML等。

71.充分利用软件的杠杆效应

Use software leverage to your advantage

想办法重复利用既有软件,将各个软件组合起来使用。

72.活用Shell脚本

Use shell scripts to increse leverage and portability

利用shell脚本加大杠杆效应,提高软件的可移植性

shell脚本能发挥巨大的杠杆效应,将shell脚本用作胶水语言(glue language,连接软件与软件的语言)。

73.避开交互式用户接口

Avoid captive user interfaces

交互式用户接口又称为捆绑型用户接口,是软件位于命令解释器的上位与用户进行对话的一种模式。这种软件从启动到运行结束,用户都无法与命令解释器对话。用户会捆绑在该软件的用户接口内部,在解除捆绑之前无法脱身。问题:

  • 程序员需记住软件各自的对话方法
  • 在软件之间无法对话
  • 等待时间变长
  • 输入部分负责解析的代码变得膨胀和不清晰
  • 产生“大就是美”的错误引导

应将控制权还给命令解释器。

74.过滤器化

Make every program a filter

让所有软件都成为过滤器。

软件的本质是处理数据,而不是生成数据。

一定要正确设计成使用标准输入输出。

*UNIX哲学的一些准则

  • 允许用户自定义环境
  • 让内核小而轻巧
  • 命名使用小写字母
  • 保护森林(尽量不用纸)
  • 沉默是金
  • 并行思考(让CPU尽可能忙碌)
  • 部件联动
  • 完成90%的目标(剩下10%让用户“自己想办法解决”)
  • 劣就是优(不高级但有价值)
  • 层次化思维

第四章 视角 程序员的视角

75.内聚度

Cohesion

模块强度

内聚度用于表示模块内功能的纯粹程度,用来衡量模块的强度。等级:

  • 1.巧合强度:“巧合”指事物恰巧一致,各元素之间并不存在特别的关系。
  • 2.逻辑强度:抽象地整合了某种功能的模块。
  • 3.时间强度:在特定的时间点,连续执行的多个功能整合而成,模块内各功能之间不存在很强的关联性。
  • 4.流程强度:由处理问题时所需的全部或部分功能组合而成,这些功能按顺序执行。
  • 5.通信强度:基本拥有流程强度模块的特性,模块内部的各功能之间会进行数据传递或引用相同的数据。
  • 6.信息强度:由处理特定数据结构的多个功能组成。基本思想是统一数据结构尽量由同一个模块来访问。
  • 7.功能强度:所有命令都为了完成一项工作而相互关联。

尽量实现功能强度模块,以高内聚为目标。

76.耦合度

Coupling

耦合度是模块之间关系密切程度的标准,测量的是两个模块之间耦合的松紧程度。等级(越高越低):

  • 1.内容耦合:模块之间存在共享部分,常在使用汇编语言编写的模块中
  • 2.公共耦合:公共区域内定义的数据由多个模块共同使用,如全局变量
  • 3.外部耦合:模块间共享外部声明的数据
  • 4.控制耦合:调用方模块以参数的形式传递涉及被调用方模块内部控制的数据。调用方必须知道被调用方的逻辑。
  • 5.特征耦合:两个模块间传递公共区域中没有的数据结构。数据结构通过参数传递,传递的数据未必会用到。
  • 6.数据耦合:模块间仅通过参数传递标量类型的数据作为模块间的接口。可以将对象模块视为黑箱。

我们应尽量降低模块间接口耦合度:

  • 尽量通过参数传递数据
  • 数据尽量不用全局变量保存
  • 不让模块的运行因外界传来的值而发生改变。

77.正交性

Orthogonality

代码应满足正交性,即代码之间应具有独立性和分离性。

78.可逆性

Reversibility

程序的判断中应时常保持可逆性,禁止使用无法还原的方案。

不存在所谓的最终状态,发生问题时要保证代码能回到之前的状态。

79.代码中的“坏味”

Bad Smell in code

  • 代码重复
  • 函数太长
  • 模块太大
  • 模块太多
  • 名称不一致

80.技术负债

Technical debt

编程有两条路,一条是花费大把时间写出整洁的代码,另一条是快速写出不整洁的代码。

后者意味着软件背上了债务。

一般原因:

  • 经验不足的程序员
  • 交付日期的压力
  • 可读性低的代码
  • 特殊化的代码
  • 无用的复杂代码
  • 低质量的设计

以下团队文化也是原因

  • 不提倡写整洁的代码
  • 接纳不明确的代码
  • 不给重构留时间
  • 发布之前才做回归测试
  • 没有勇气替换包含大量依赖关系的旧系统
  • 随意创建分支

改善动作要慢且精。

第五章 习惯 程序员的日常

81.程序员的三大美德

Three great virtues of programmer

程序员要懒惰、急躁和傲慢。

  • 懒惰:不遗余力地减少整体劳力的消耗。应编写高效的代码。让重复的工作结构化。
  • 急躁:在计算机偷懒的时候会感到愤怒。在工作时要预想那些问题会发生,提前思考。
  • 傲慢:拥有极强的自尊心,促使自己写出让别人挑不出毛病的代码。

82.童子军规则

Boy Scout Rule

“离开自己所在的地方时,这个地方必须比来时更干净”

代码要改善之后再提交,讲究稳中求胜。

83.性能调优的箴言

Proverb of performance tuning

好的代码胜过快的代码

  • 不要再编程之初就对代码进行优化
  • 编程之初暂时不要对代码进行优化

我们要先写高质量的代码,然后根据需要进行优化。

在对代码进行优化时:

  • 证明优化的必要性
  • 测量性能,找出瓶颈
  • 优化瓶颈部分的代码
  • 测量性能,确认优化效果
  • 验证优化后的代码是否存在运行问题

84.无我编程

Egoless programming

舍弃自我(自负和自尊),与他人合作。十诫:

  • 你不同于你的代码
  • 人外有人天外有天
  • 不要在没有沟通的情况下重写代码
  • 对技不如己者要尊敬,并且有耐心
  • 世上唯一不变的就是变化
  • 真正的权威来自知识而不是地位
  • 为信仰而战,但也要坦诚面对失败
  • 不能闭门造车
  • 宽待他人,严待代码,批评的对象是代码而不是人

85.一步一步走

One by one

一件一件做,一点一点来,步步为营。

  • 想立刻获得答案的态度是不正确的。一眼看不出答案时应当继续思考
  • 没有经过深思熟虑就下结论的做法是错误的,发现某个东西可以满足条件时不能想当然,要探讨其他的可能性
  • 避免反复思考同一件事
  • 直接用脑子思考有些困难,不如边写边思考
  • 直觉对逻辑思考来说也很重要

86.TMTOWTDI

There’s more than one way to do it.

做法不止一个

工具/对象/方法应具备多样性

第六章 手法 程序员的工具箱

87.曳光弹

Tracer ammunition

编程中的曳光弹指先对那些想要优先检验的部分进行编程。

先编写能够运行起来的基础部分,再慢慢添加其他内容。

88.契约式设计

Design by Contract

严格遵守契约能保证代码的正确性,能使代码保持简洁,容易提早发现问题。

89.防御性编程

Defensive programming

防范于未然的程序设计。

我们需要采用“路障战术”

对于预想之内的错误,一般有如下几种处理:

  • 返回无害的指,如0
  • 使用下一个数据,返回下一个有效数据
  • 返回和前面一样的值
  • 使用近似值
  • 在日志中记录警告信息
  • 返回错误
  • 调用错误处理函数
  • 显示错误信息
  • 终止处理
  • 各部分选择最合适的方式处理错误

90.内部测试

Dogfooding Eating your own dog food

从用户的角度出发,以用户的身份使用软件,试尝软件的“味道”

91.橡皮鸭调试法

Rubber ducking

再编程过程中,我们要把出现的问题或者有问题的代码说给“某个人”(可能是小黄鸭)听,这一我们就能找到问题出现的原因。

92.语境

Context

在语境中对话,结合语境思考。

代码通用化应注意语境

  • 通用化的部分有时需要分别进行修改
  • 修改通用化部分时的影响程度上升

*亚里士多德将知识氛围客观知识(科学)、技术知识(工学)和实践知识三类。

第七章 法则 编程的反模式

93.布鲁克斯法则

Brooks’s law

增员等于“火上浇油”

94.康威定律

Conway’s law

软件结构(架构)反映了创建它的组织的结构。

应先设计架构再编排组织结构

95.破窗效应

Broken Windows Theory

96.熵增原理

Law of entropy increase

代码会自然而然地开始腐败,如果不对代码进行管理,其混乱程度就会不断加深,直至突破极限。

97.80-10-10原则

80-10-80 rule

我们在用高水平的工具或语言开发软件时,可以在非常短的时间内实现用户80%的需求,而在剩下20%的需求中,有10%的需求需要通过一定的努力才能实现,剩下10%完全不可能实现。

使用单一工具很难在所有领域都获得完美的效果。对症药要比万能药好用。

98.约书亚树原则

Joshua Tree Principle(JTP)

人们在知道某个东西的名字后就会注意到这个东西,反而如果某东西没有名字,人们就很难注意它。

我们要创造语言,然后在团队中共享。这就需要用到通用语言(Ubiquitous Language,UL)

99.第二系统综合征

Second system syndrome

第二次发布总会出现功能过多、质量差的情况。

在开发第二版软件时,我们掌握了更多的信息,也有了自信,所以倾向于把之前保留的功能以及新想到的功能一股脑儿加进去。

程序员要有自制力,避免陷入多功能主义的怪圈。一个有效的做法就是重新对用户进行定义并将用户具像化。

  • 用户是谁
  • 用户需要什么
  • 用户认为什么是必要的
  • 用户想要什么

100.重新发明车轮

Reinvented wheel,Reinventing the wheel

原因:

  • 不知道车轮
  • 想制作车轮

我们要避免重新发明车轮,将重点放在本来应该做的工作上。

但是为了商业目的、学习目的时,允许重新发明车轮。

101.给牦牛剃毛

Yak Shaving

在解决问题的过程中总有新的问题冒出来,我们难以抓住问题的本质。

当我们发觉自己已经陷入给牦牛剃毛的状态时,应停下脚步,会想自己原本要实现的目标是什么。